/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
/**
 * 表单验证
 * 验证规则：
 * 1、验证对象：input/textare类型的表单元素，元素包含自定义属性datatype
 * 2、可做即时校验或提交时校验
 * 3、支持同时绑定多个表单的校验操作
 * 4、兼容firefox、chrome及ie8+
 * 5、验证规则：根据datatype定义的规则进行规则验证。具体规则解释如下：
 *		内置基本的datatype类型有： * | *6-16 | n | n6-16 | s | s6-18 | p | m | e | c
 *		*：检测是否有输入，可以输入任何字符，不留空即可通过验证；
 *		*6-16：检测是否为6到16位任意字符；
 *		n：数字类型；
 *		n6-16：6到16位数字；
 *		s：字符串类型；
 *		s6-18：6到18位字符串；
 *		m：手机号码格式；
 *		e：email格式；
 *		c：验证字符串是否为身份证号。
 *		p：验证是否为4-35位的a-zA-Z0-9_@组成的密码。
 *
 * @version {string} v1.0.1
 * @author {zh_cn} FigoerStudio
 * @url {url} http://www.lpfin.com/
 * @date {datetime} 2014-04-09
 * @params {object} options {
 *		form: // 一个form id 或多个form id数组
 *		msgId: // 出错提示信息div ID，默认无则在每个表单项后面插入一个span提示div
 *		msgCss: // 出错提示信息样式 样式串如"color:#ccc;border:1px solid #ccc;"
 *		invalid: // 开启特殊字符校验 true|false
 *		invalidMsg: // 开启特殊字符验证时的错误提示
 *		checkEmpty: // 是否对空字符校验,默认true校验（此参数仅在验证方式为submit时有效）
 *		type: // 表单验证方式 'rightnow'：即时,'submit'：提交,'default':即时+提交
 * }
 */
var formValid = function(options) {
    //var gErrorFlag = false; // 出错标记位
    //var gErrorDom = null; // 记录一个出错节点
    var gFormList = []; // 表单对象数组

    if ("object" !== typeof options) {
        return;
    }

    var opt = {
        form: options.form,
        msgId: options.msgId || null,
        msgCss: options.msgCss || null,
        invalid: options.invalid || false,
        invalidMsg: options.invalidMsg || '所填写包含特殊字符，请正确输入。',
        checkEmpty: options.checkEmpty || true,
        type: options.type
    };

    if ("string" === typeof opt.form) {
        gFormList.push(document.getElementById(opt.form));
    } else {
        var _fIds = opt.form;
        for (var i =0; i<_fIds.length;i++) {
            gFormList.push(document.getElementById(_fIds[i]));
        }
    }

    for(var j=0; j<gFormList.length; j++) {
        // 获取每个表单的input/textarea字段
        var _form = gFormList[j];
        var inputElements = _form.getElementsByTagName('input');
        var textElements = _form.getElementsByTagName('textarea');
        for(var k1=0;k1<inputElements.length;k1++) {
            var _ele = inputElements[k1];
            var _eleValid = _ele.getAttribute("datatype");
            var _errormsg = _ele.getAttribute("errormsg");
            var func = new Func(_ele, _eleValid, _errormsg);
            _ele.onfocus = func._funcFocus;
            if (null != _eleValid) {
                _ele.onblur = func._checkField;;
            }
        }

        for(var k1=0;k1<textElements.length;k1++) {
            var _ele = textElements[k1];
            var _eleValid = _ele.getAttribute("datatype");
            var _errormsg = _ele.getAttribute("errormsg");
            var func = new Func(_ele, _eleValid, _errormsg);
            _ele.onfocus = func._funcFocus;
            if (null != _eleValid) {
                _ele.onblur = func._checkField;
            }
        }

        // 绑定提交校验操作
        if ('rightnow' !== opt.type) {
            var _funcForm = new FuncForm(inputElements, textElements);
            _form.onsubmit = _funcForm._checkField;
        }
    }

    function FuncForm(ies, tes) {
        this._checkField = function() {
            for(var k1=0;k1<ies.length;k1++) {
                var _ele = ies[k1];
                var _eleValid = _ele.getAttribute("datatype");
                var _errormsg = _ele.getAttribute("errormsg");
                var func = new Func(_ele, _eleValid, _errormsg, 'submit');
                if (!func._checkField()) {
                    return false;
                }
            }

            for(var k1=0;k1<tes.length;k1++) {
                var _ele = tes[k1];
                var _eleValid = _ele.getAttribute("datatype");
                var _errormsg = _ele.getAttribute("errormsg");
                var func = new Func(_ele, _eleValid, _errormsg, 'submit');
                if (!func._checkField) {
                    return false;
                }
            }
        }
    }
    // {{{ _okStyle
    var _okStyle = function(obj) {
        var flag = obj.getAttribute("flag");
        if ("error" == flag) {
            //gErrorFlag = false; // 全局出错标志位置为false
            //gErrorDom = null;
            obj.setAttribute("flag", "normal");// 设置标识为正常
            obj.style.border = "1px solid #999999";
            obj.style.backgroundColor= "#FEFEFE";
            if (null != opt.msgId) {
                document.getElementById(opt.msgId).innerHTML = "";
                document.getElementById(opt.msgId).style.display = "none";
            } else {
                if (obj.nextSibling) {
                    obj.parentNode.removeChild(obj.nextSibling);
                }
            }
        }
        return;
    }
    // }}}
    // {{{ _errStyle
    var _errStyle = function(obj, msg) {
        //gErrorFlag = true; // 全局出错标志位置为true
        //gErrorDom = obj;
        obj.setAttribute("flag", "error");// 设置标识错误信息
        if (null == msg || '' == msg) {
            msg = "您的输入有误！";
        }

        if (null != opt.msgId) {
            if ("submit" !== opt.type) {
                obj.style.border = "1px solid #ffc0cb";
                obj.style.backgroundColor= "#ffc0cb";
            }
            var msgDom = document.getElementById(opt.msgId);
            if (null !== opt.msgCss) {
                var _es = msgDom.getAttribute("style");
                msgDom.setAttribute("style", _es + ";" +opt.msgCss);
            }
            msgDom.innerHTML = msg;
            msgDom.style.display = "";
        } else {
            var _errDom = document.createElement("span");
            _errDom.id = "error_message_" + (obj.id || Math.random());
            _errDom.style.color = "#FFC0CB";
            _errDom.innerHTML = msg;
            if ("submit" !== opt.type) {
                obj.style.border = "1px solid #ffc0cb";
                obj.style.backgroundColor= "#ffc0cb";
                if (null !== opt.msgCss) {
                    var _es = _errDom.getAttribute("style");
                    _errDom.setAttribute("style", _es + ";" +opt.msgCss);
                }
            } else {
                _errDom.style.display = "none";
            }

            if(obj.nextSibling) { // 如果存在下一子结点 在下一子结点前插入子结点  
                obj.parentNode.insertBefore(_errDom, obj.nextSibling);
            } else{ // 如果没有下一子结点向后追加子结点  
                obj.parentNode.appendChild(_errDom);
            }
        }
        return;
    }
    // }}}

    function Func(ele, fvalid, errormsg, checkType) {
        if ("undefined" === typeof checkType) {
            checkType = "onblur";
        }

        var _t = this;
        this._checkField = function() {
            // 解析valid规则
            var fvalue = ele.value;
            if ("" == fvalue) {
                if (opt.checkEmpty && "submit" == checkType) {
                    _errStyle(ele, "输入项不能为空！");
                    return false;
                } else {
                    return true;
                }
            }

            // 特殊字符校验
            if (opt.invalid && _t._hasInvalid(fvalue)) {
                _errStyle(ele, opt.invalidMsg);
                return false;
            }

            var vType = fvalid.substring(0, 1);
            var vScope = fvalid.substring(1).split("-");
            var vScopeFrom = vScope[0];
            var vScopeTo = vScope[1];
            switch(vType) {
            case "*":
            case "s":
                if (vScopeFrom && vScopeFrom > fvalue.length || 
                        vScopeTo && vScopeTo < fvalue.length) {
                    _errStyle(ele, errormsg);
                    return false;
                }
                break;
            case "n":
                if (isNaN(fvalue) ||
                        vScopeFrom && vScopeFrom > fvalue.length ||
                        vScopeTo && vScopeTo < fvalue.length) {
                    _errStyle(ele, errormsg);
                    return false;
                }
                break;
            case "m":
            case "e":
            case "c":
            case "p":
                if (!_t._is(vType, fvalue)) {
                    _errStyle(ele, errormsg);
                    return false;
                }
                break;
            }
            return true;
        }

        this._funcFocus = function() {
            _okStyle(ele);
        }

        /*
         * 正则验证规则
         *
         * @params string t 验证规则类型 m|c|e|p
         * @params string s 要验证的字符串
         * @return boolean true|false
         */
        this._is = function(t, s){
            switch(t) {
            case "m": // phone
                var myReg =/^(13|15|18)\d{9}$/;
                break;
            case "e": // mail
                var myReg = /^[-_A-Za-z0-9.]+@([_A-Za-z0-9]+\.)+[A-Za-z0-9]+$/; 
                break;
            case "c": // id card
                var myReg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/; 
                break;
            case "p": // password
                var myReg = /^[a-zA-Z0-9_@]{4,36}$/;
                break;
            }

            var re = new RegExp(myReg);
            if (re.test(s)) {
                return true;
            }else{
                return false;
            }
        }

        /**
         * 特殊字符校验
         *
         */
        this._hasInvalid = function(str) {
            var _invalid = /[`~!#\$%\^\&\*\(\)\+<>\?:"\{\},\\\/;'\[\]]/im;
            if (-1 != str.search(_invalid)) {
                return true;
            }
            return false;
        }
    }

    return this;
}

